package com.ruoyi.asset.roadgreening.service.impl;

import com.ruoyi.asset.common.scopecode.constant.ServiceCode;
import com.ruoyi.asset.common.scopecode.service.IScopeCodeService;
import com.ruoyi.asset.homepage.constant.CommunityConstant;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.asset.homepage.constant.ServiceTypeConstant;
import com.ruoyi.asset.roadgreening.constant.RoadGreeningDirtConstant;
import com.ruoyi.asset.roadgreening.domain.RoadGreening;
import com.ruoyi.asset.roadgreening.domain.bo.*;
import com.ruoyi.asset.roadgreening.domain.vo.GreeneryCommunityCountVo;
import com.ruoyi.asset.roadgreening.domain.vo.GreeneryCommunityMapVo;
import com.ruoyi.asset.roadgreening.domain.vo.GreeneryWorkStatisticsVo;
import com.ruoyi.asset.roadgreening.domain.vo.RoadGreeningVo;
import com.ruoyi.asset.roadgreening.mapper.RoadGreeningMapper;
import com.ruoyi.asset.roadgreening.service.IRoadGreeningService;
import com.ruoyi.asset.tool.domain.bo.ToolStatisticsBo;
import com.ruoyi.asset.tool.service.IToolService;
import com.ruoyi.asset.workman.service.IWorkmanService;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.entity.SysDictData;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.tools.excel.MyExcelUtil;
import com.ruoyi.common.tools.excel.base.MyExcelResult;
import com.ruoyi.common.tools.excel.listener.asset.RoadGreeningExcelListener;
import com.ruoyi.common.tools.utils.SerialGenerator;
import com.ruoyi.common.utils.BeanCopyUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.erecord.region.service.IRegionService;
import com.ruoyi.standingbook.greenery.service.IGreeneryService;
import com.ruoyi.system.service.ISysDictDataService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * 道路绿化管养任务完成进度Service业务层处理
 *
 * @author cc
 * @date 2023-08-29
 */
@RequiredArgsConstructor
@Service
public class RoadGreeningServiceImpl implements IRoadGreeningService {

	private final RoadGreeningMapper baseMapper;
	private final IWorkmanService workmanService;
	private final IToolService toolService;
	private final ISysDictDataService sysDictDataService;
	private final IRegionService regionService;
	private final IScopeCodeService scopeCodeService;
	private final IGreeneryService greeneryService;

	private Boolean batchInsertOrUpdate(List<RoadGreening> voList) {
		return this.baseMapper.insertOrUpdateBatch(voList);
	}

	@Override
	public List<String> importExcel(String excelUrl) {
		List<String> errorMsgList = new ArrayList<>();

		// 生成批次号
		final String batchNo = SerialGenerator.generator.nextId();

		// excel 处理
		MyExcelResult<RoadGreeningVo> excelResult = MyExcelUtil.getImportExcelData(batchNo, excelUrl,
				new RoadGreeningExcelListener(batchNo), RoadGreeningVo.class, true);

		if (null == excelResult) {
			errorMsgList.add("未获取到要处理的数据");

			return null;
		}

        /**
         *  有解析失败就直接返回错误信息
         */
        if(!excelResult.getErrorList().isEmpty()) {
            return excelResult.getErrorList();
        }

		if (!excelResult.getList().isEmpty()) {
			List<RoadGreening> list = new ArrayList<>();
            AtomicInteger row = new AtomicInteger(0);
			excelResult.getList().forEach(item -> {
                int currentRow = row.incrementAndGet();
				if (item.getDataCheckResult().isSucess()) {
					RoadGreening roadGreening = new RoadGreening();

					BeanCopyUtils.copy(item, roadGreening);

					RoadGreening oldRoadGreening = getVoByNameAndType(roadGreening.getRoadName(),
							roadGreening.getMaintenanceType());

					if (oldRoadGreening != null) {
						roadGreening.setId(oldRoadGreening.getId());
					} else {
						String scopeCode = null;

						try {
							scopeCode = scopeCodeService.getNextScopeCode(ServiceCode.GREENERY,
									roadGreening.getMaintenanceType(), "");
						} catch (Exception e) {
							errorMsgList.add("获取道路编码失败，失败原因：" + e.getMessage());
						}

						roadGreening.setRoadCode(scopeCode);
					}

                    /**
                     *  如果各行数据校验通过，再遍历检查是否数据重复
                     */
                    if(excelResult.getValidateList().isEmpty()) {
                        AtomicInteger count = new AtomicInteger(0);
                        list.stream().anyMatch(f -> {
                            int currentCount = count.incrementAndGet();
                            if (f.getRoadName().equals(roadGreening.getRoadName()) && f.getMaintenanceType().equals(roadGreening.getMaintenanceType())) {
                                errorMsgList.add(String.format("第%d行数据检查失败，失败原因：与第%s行数据重复", currentRow, currentCount));
                                return true;
                            }
                            return false;
                        });
                    }

					list.add(roadGreening);
				} else {
					errorMsgList.add(String.format("第 %d 行数据检查失败，失败原因：%s", excelResult.getList().indexOf(item) + 1,
							item.getDataCheckResult().getMsg()));
				}
			});

			if (errorMsgList.isEmpty()) {
				batchInsertOrUpdate(list);
			}
		}

		return errorMsgList;
	}

	private RoadGreening getVoByNameAndType(String roadName, String maintenanceType) {
		LambdaQueryWrapper<RoadGreening> lqw = Wrappers.lambdaQuery();

		lqw.eq(RoadGreening::getRoadName, roadName);
		lqw.eq(RoadGreening::getMaintenanceType, maintenanceType);
		lqw.eq(RoadGreening::getDelFlag, 0);

		List<RoadGreening> list = baseMapper.selectList(lqw);

		return list.isEmpty() ? null : list.get(0);
	}

	@Override
	public int deleteMaintenanceScope(Set<Long> idsSet) {
		if (CollectionUtils.isEmpty(idsSet)) {
			return -1;
		}

		return baseMapper.logicDeleteMaintenanceScope(idsSet);
	}

	@Override
	public TableDataInfo<RoadGreeningVo> queryMaintenanceScope(MaintenanceScopeSearchBo searchBo, PageQuery pageQuery) {
		Page<RoadGreeningVo> result = baseMapper.selectMaintenanceScopeWithPage(pageQuery.build(), searchBo);

		return TableDataInfo.build(result);
	}

	@Override
	public List<RoadGreeningVo> queryMaintenanceScope(MaintenanceScopeSearchBo searchBo) {
		return baseMapper.exportMaintenanceScope(searchBo);
	}

	@Override
	public RoadGreeningOverviewBo getRoadGreeningOverview() {
        RoadGreeningOverviewBo statisticsBo = new RoadGreeningOverviewBo();
        RoadGreeningOverviewBo roadGreeningOverviewBo = baseMapper.getTreeCountAndArea();
        if (null != roadGreeningOverviewBo) {
            statisticsBo.setGreenArea(roadGreeningOverviewBo.getGreenArea());
            statisticsBo.setTreeCount(roadGreeningOverviewBo.getTreeCount());
        } else {
            statisticsBo.setGreenArea(0.00);
            statisticsBo.setTreeCount(0);
        }
		int workCount = workmanService.getByServiceType(ServiceTypeConstant.GREENERY);
		statisticsBo.setWorkerCount(workCount);

		ToolStatisticsBo toolStatisticsBo = toolService.getCountByServiceType(ServiceTypeConstant.GREENERY);
		if (null != toolStatisticsBo) {
            statisticsBo.setEquipmentCount(toolStatisticsBo.getToolCount());
            statisticsBo.setVehicleCount(toolStatisticsBo.getVehicleCount());
        } else {
            statisticsBo.setEquipmentCount(0);
            statisticsBo.setVehicleCount(0);
        }

		return statisticsBo;
	}

	@Override
	public List<StatisticianGreeneryByRegion> statForGreeneryByRegion() {
		List<StatisticianGreeneryByRegion> list = baseMapper.statForGreeneryByRegion();

		list.forEach(item -> {
			ToolStatisticsBo toolStat = toolService.getCountByServiceTypeAndCommunity(ServiceTypeConstant.GREENERY,
					item.getCommunityId());

			item.setEquipmentCount(toolStat.getToolCount());
			item.setVehicleCount(toolStat.getVehicleCount());

			int workCount = workmanService.getCommunityByServiceType(ServiceTypeConstant.GREENERY,
					item.getCommunityId());
			item.setWorkerCount(workCount);
		});

		return list;
	}

	@Override
	public Map getRoadGreeningCommunityCount() {
		HashMap<String, RoadGreeningCommunityBo> map = new HashMap<>();
		SysDictData sysDictData = new SysDictData();
		sysDictData.setDictType(CommunityConstant.COMMUNITY_TYPE);
		List<SysDictData> data = sysDictDataService.selectDictDataList(sysDictData);
		for (SysDictData community : data) {
			String communityNo = regionService.getRegionIdByName(community.getDictLabel());
			List<RoadGreeningTypeBo> roadGreeningCommunityCount = baseMapper.getRoadGreeningCommunityCount(communityNo);
			roadGreeningCommunityCount.forEach(e -> {
				String roadGreeningType = sysDictDataService.selectDictLabel(RoadGreeningDirtConstant.GREENERY,
						e.getMaintenanceType());
				if (StringUtils.isNotBlank(roadGreeningType)) {
					e.setMaintenanceType(roadGreeningType);
				}
			});
			RoadGreeningCommunityBo roadGreeningCommunityBo = new RoadGreeningCommunityBo();
			roadGreeningCommunityBo.setRoadGreeningTypeBoList(roadGreeningCommunityCount);
			ToolStatisticsBo toolCount = toolService.getCountByServiceTypeAndCommunity(ServiceTypeConstant.GREENERY,
					communityNo);
			roadGreeningCommunityBo.setToolCount(toolCount.getToolCount());
			roadGreeningCommunityBo.setVehicleCount(toolCount.getVehicleCount());
			int workmanCount = workmanService.getCommunityByServiceType(ServiceTypeConstant.GREENERY, communityNo);
			roadGreeningCommunityBo.setWorkmanCommunity(workmanCount);
			map.put(community.getDictLabel(), roadGreeningCommunityBo);
		}

		return map;
	}

    @Override
    public List<GreeneryCommunityCountVo> getCleaningCountByCommunity(String date) {
        SysDictData sysDictData = new SysDictData();
        sysDictData.setDictType(CommunityConstant.COMMUNITY_TYPE);
        List<SysDictData> communities = sysDictDataService.selectDictDataList(sysDictData);
        ArrayList<GreeneryCommunityCountVo> greeneryCommunityCountVos = new ArrayList<>();
        communities.forEach(e->{
            GreeneryCommunityCountVo communityCountVo = new GreeneryCommunityCountVo();
            communityCountVo.setCommunity(e.getDictLabel());
            String regionId = regionService.getRegionIdByName(e.getDictLabel());
            GreeneryCommunityCountVo greeneryCommunityCountVo = baseMapper.selectGreeneryCountByCommunity(date, regionId);
            if (null != greeneryCommunityCountVo){
                communityCountVo.setNumSum(greeneryCommunityCountVo.getNumSum());
                communityCountVo.setAreaSum(greeneryCommunityCountVo.getAreaSum());
            } else {
                communityCountVo.setNumSum(0);
                communityCountVo.setAreaSum(0.00);
            }
            ToolStatisticsBo toolCount = toolService.getCommunityByServiceTypeAndDate(ServiceTypeConstant.GREENERY, regionId,date);
            if (null != toolCount) {
                communityCountVo.setEquipmentCount(toolCount.getToolCount());
                communityCountVo.setVehicleCount(toolCount.getVehicleCount());
            } else {
                communityCountVo.setEquipmentCount(0);
                communityCountVo.setVehicleCount(0);
            }
            int workmanCount = workmanService.getCommunityByServiceTypeAndDate(ServiceTypeConstant.GREENERY, regionId,date);
            communityCountVo.setWorkerCount(workmanCount);
            greeneryCommunityCountVos.add(communityCountVo);
        });
        return greeneryCommunityCountVos;
    }

    @Override
    public GreeneryWorkStatisticsVo getGreeneryWorkByDate(String date) {
        GreeneryWorkStatisticsVo greeneryWorkStatisticsVo = new GreeneryWorkStatisticsVo();
        SysDictData sysDictData = new SysDictData();
        sysDictData.setDictType(CommunityConstant.COMMUNITY_TYPE);
        List<SysDictData> communities = sysDictDataService.selectDictDataList(sysDictData);
        ArrayList<BigDecimal> areaList = new ArrayList<>();
        communities.forEach(e->{
            String regionId = regionService.getRegionIdByName(e.getDictLabel());
            GreeneryCommunityCountVo greeneryCommunityCountVo = baseMapper.selectGreeneryCountByCommunity(date, regionId);
            if (null != greeneryCommunityCountVo){
                areaList.add(BigDecimal.valueOf(greeneryCommunityCountVo.getAreaSum()));
            } else {
                areaList.add(BigDecimal.ZERO);
            }
        });
        BigDecimal totalArea = areaList.stream().reduce(BigDecimal::add).orElse(BigDecimal.ZERO);
        greeneryWorkStatisticsVo.setTotalArea(totalArea);
        BigDecimal finishedAreaSum = greeneryService.getSumByDate(date);
        if (finishedAreaSum == null) {
            finishedAreaSum = BigDecimal.valueOf(0);
        }
        greeneryWorkStatisticsVo.setFinishedAreaSum(finishedAreaSum);
        if (finishedAreaSum.compareTo(BigDecimal.ZERO) <= 0 || totalArea.compareTo(BigDecimal.ZERO) <= 0){
            greeneryWorkStatisticsVo.setPercent(BigDecimal.ZERO);
        } else {
            BigDecimal pec = finishedAreaSum.divide(totalArea, 2, RoundingMode.HALF_UP)
                .multiply(BigDecimal.valueOf(100));
            pec = pec.compareTo(BigDecimal.valueOf(100)) > 0 ? BigDecimal.valueOf(100) : pec;
            greeneryWorkStatisticsVo.setPercent(pec);
        }
        return greeneryWorkStatisticsVo;
    }

    @Override
    public GreeneryWorkStatisticsVo getGreeneryWorkByDateAndCommunity(String date, String community) {
        GreeneryWorkStatisticsVo greeneryWorkStatisticsVo = new GreeneryWorkStatisticsVo();
        String regionId = regionService.getRegionIdByName(community);
        GreeneryCommunityCountVo greeneryCommunityCountVo = baseMapper.selectGreeneryCountByCommunity(date, regionId);
        if (null != greeneryCommunityCountVo){
            greeneryWorkStatisticsVo.setTotalArea(BigDecimal.valueOf(greeneryCommunityCountVo.getAreaSum()));
        } else {
            greeneryWorkStatisticsVo.setTotalArea(BigDecimal.ZERO);
        }
        BigDecimal totalArea = greeneryWorkStatisticsVo.getTotalArea();
        if(totalArea == null) {
            totalArea = BigDecimal.valueOf(0);
        }
        BigDecimal finishedAreaSum = greeneryService.getSumByDateAndCommunity(date,community);
        if(finishedAreaSum == null) {
            finishedAreaSum = BigDecimal.valueOf(0);
        }
        greeneryWorkStatisticsVo.setFinishedAreaSum(finishedAreaSum);
        if (finishedAreaSum.compareTo(BigDecimal.ZERO) <= 0|| totalArea.compareTo(BigDecimal.ZERO) <= 0){
            greeneryWorkStatisticsVo.setPercent(BigDecimal.ZERO);
        } else {
            BigDecimal pec = finishedAreaSum.divide(totalArea, 2, RoundingMode.HALF_UP)
                .multiply(BigDecimal.valueOf(100));
            pec = pec.compareTo(BigDecimal.valueOf(100)) > 0 ? BigDecimal.valueOf(100) : pec;
            greeneryWorkStatisticsVo.setPercent(pec);
        }
        return greeneryWorkStatisticsVo;
    }

    @Override
    public GreeneryCommunityMapVo getCommunityByDate(String community, String date) {
        HashMap<String, String> map = new HashMap<>(32);
        String communityNo = regionService.getRegionIdByName(community);
        SysDictData sysDictData = new SysDictData();
        sysDictData.setDictType(RoadGreeningDirtConstant.GREENERY);
        List<SysDictData> data = sysDictDataService.selectDictDataList(sysDictData);
        List<RoadGreeningTypeBo> roadGreeningTypeBos = baseMapper.getRoadGreeningCommunityCount(communityNo);
        buildCleaningTypeMap(data,roadGreeningTypeBos,map);
        GreeneryCommunityMapVo greeneryCommunityMapVo = new GreeneryCommunityMapVo();
        greeneryCommunityMapVo.setGreeneryTypeMap(map);
        ToolStatisticsBo toolCount = toolService.getCountByServiceTypeAndCommunity(ServiceTypeConstant.GREENERY, communityNo);
        greeneryCommunityMapVo.setToolCount(toolCount.getToolCount());
        greeneryCommunityMapVo.setVehicleCount(toolCount.getVehicleCount());
        int workmanCount = workmanService.getCommunityByServiceType(ServiceTypeConstant.GREENERY, communityNo);
        greeneryCommunityMapVo.setWorkmanCommunity(workmanCount);
        return greeneryCommunityMapVo;
    }

    @Override
    public GreeneryCommunityCountVo getGreeneryByDateAndCommunity(String date, String community) {
        GreeneryCommunityCountVo countVo;
        if (StringUtils.isNotEmpty(community)) {
            String regionId = regionService.getRegionIdByName(community);
            countVo = baseMapper.selectGreeneryCountByCommunity(date, regionId);
        } else {
            countVo = baseMapper.selectGreeneryCountByCommunity(date, null);
        }
        if (null == countVo) {
            countVo = new GreeneryCommunityCountVo();
            countVo.setAreaSum(0d);
            countVo.setNumSum(0);
        }

        return countVo;
    }

    /**
     * 组装数据
     * @param data
     * @param roadGreeningTypeBos
     * @param map
     */
    private void buildCleaningTypeMap(List<SysDictData> data, List<RoadGreeningTypeBo> roadGreeningTypeBos, HashMap<String, String> map){
        ArrayList<String> typeName = new ArrayList<>();
        for (SysDictData roadGreeningType : data) {
            if (roadGreeningTypeBos.size() > 0) {
                for (RoadGreeningTypeBo greeningTypeBo : roadGreeningTypeBos) {
                    if (roadGreeningType.getDictValue().equals(greeningTypeBo.getMaintenanceType())) {
                        typeName.add(roadGreeningType.getDictLabel());
                        map.put(roadGreeningType.getDictLabel(),greeningTypeBo.getAreaOrNum() + "");
                    }
                }
            } else {
                map.put(roadGreeningType.getDictLabel(),"0");
            }
        }
        if (typeName.size() > 0) {
            List<String> labelList = data.stream().map(SysDictData::getDictLabel).collect(Collectors.toList());
            labelList.removeAll(typeName);
            labelList.forEach(e->{
                map.put(e,"0");
            });
        }
    }
}
